using System;
using System.Diagnostics.CodeAnalysis;
using System.Threading;

namespace Microsoft.Xna.Framework
{
	public class GameComponent : IGameComponent, IUpdateable, IDisposable
	{
		private bool _enabled = true;
		private int _updateOrder;
		private readonly Game _game;
		private EventHandler<EventArgs> _enabledChanged;
		private EventHandler<EventArgs> _updateOrderChanged;
		private EventHandler<EventArgs> _disposed;

		public bool Enabled
		{
			get
			{
				return _enabled;
			}
			set
			{
				if (_enabled == value)
					return;
				_enabled = value;
				OnEnabledChanged(this, EventArgs.Empty);
			}
		}

		public int UpdateOrder
		{
			get
			{
				return _updateOrder;
			}
			set
			{
				if (_updateOrder == value)
					return;
				_updateOrder = value;
				OnUpdateOrderChanged(this, EventArgs.Empty);
			}
		}

		public Game Game
		{
			get
			{
				return _game;
			}
		}

		public event EventHandler<EventArgs> EnabledChanged
		{
			add
			{
				EventHandler<EventArgs> eventHandler = _enabledChanged;
				EventHandler<EventArgs> comparand;
				do
				{
					comparand = eventHandler;
					eventHandler = Interlocked.CompareExchange(ref _enabledChanged, comparand + value, comparand);
				}
				while (eventHandler != comparand);
			}
			remove
			{
				EventHandler<EventArgs> eventHandler = _enabledChanged;
				EventHandler<EventArgs> comparand;
				do
				{
					comparand = eventHandler;
					eventHandler = Interlocked.CompareExchange(ref _enabledChanged, comparand - value, comparand);
				}
				while (eventHandler != comparand);
			}
		}

		public event EventHandler<EventArgs> UpdateOrderChanged
		{
			add
			{
				EventHandler<EventArgs> eventHandler = _updateOrderChanged;
				EventHandler<EventArgs> comparand;
				do
				{
					comparand = eventHandler;
					eventHandler = Interlocked.CompareExchange(ref _updateOrderChanged, comparand + value, comparand);
				}
				while (eventHandler != comparand);
			}
			remove
			{
				EventHandler<EventArgs> eventHandler = _updateOrderChanged;
				EventHandler<EventArgs> comparand;
				do
				{
					comparand = eventHandler;
					eventHandler = Interlocked.CompareExchange(ref _updateOrderChanged, comparand - value, comparand);
				}
				while (eventHandler != comparand);
			}
		}

		public event EventHandler<EventArgs> Disposed
		{
			add
			{
				EventHandler<EventArgs> eventHandler = _disposed;
				EventHandler<EventArgs> comparand;
				do
				{
					comparand = eventHandler;
					eventHandler = Interlocked.CompareExchange(ref _disposed, comparand + value, comparand);
				}
				while (eventHandler != comparand);
			}
			remove
			{
				EventHandler<EventArgs> eventHandler = _disposed;
				EventHandler<EventArgs> comparand;
				do
				{
					comparand = eventHandler;
					eventHandler = Interlocked.CompareExchange(ref _disposed, comparand - value, comparand);
				}
				while (eventHandler != comparand);
			}
		}

		public GameComponent(Game game)
		{
			_game = game;
		}

		~GameComponent()
		{
			Dispose(false);
		}

		public virtual void Initialize()
		{
		}

		public virtual void Update(GameTime gameTime)
		{
		}

		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (!disposing)
				return;
			lock (this)
			{
				if (Game != null)
					Game.Components.Remove(this);
				if (_disposed == null)
					return;
				_disposed(this, EventArgs.Empty);
			}
		}

		[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
		protected virtual void OnUpdateOrderChanged(object sender, EventArgs args)
		{
			if (_updateOrderChanged == null)
				return;
			_updateOrderChanged((object)this, args);
		}

		[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
		protected virtual void OnEnabledChanged(object sender, EventArgs args)
		{
			if (_enabledChanged == null)
				return;
			_enabledChanged((object)this, args);
		}
	}
}